/**
* @file fetcher.go
* @name 包下载与解压模块
* @desc 实现从远程仓库下载包并解压到本地的功能
* @version 0.1
 */

package pkgman

import (
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

// 下载包
func (pm *PackageManager) DownloadPackage(metadata PackageMetadata) (string, error) {
	// 创建缓存路径
	cachePath := filepath.Join(pm.cacheDir, "packages", fmt.Sprintf("%s-%s.egg", metadata.Name, metadata.Version))

	// 检查缓存
	if _, err := os.Stat(cachePath); err == nil {
		// 验证校验和
		if pm.config.VerifySSL {
			checksum, err := calculateChecksum(cachePath)
			if err != nil {
				return "", fmt.Errorf("计算缓存文件校验和失败: %v", err)
			}

			if checksum != metadata.Checksum {
				// fmt.Println("缓存文件校验和不匹配，重新下载")
				os.Remove(cachePath)
			} else {
				// fmt.Printf("使用缓存的 %s@%s\n", metadata.Name, metadata.Version)
				//从缓存中读取包并安装解压
				return cachePath, nil
			}
		}
	}

	// 创建缓存目录
	cacheDir := filepath.Dir(cachePath)
	if _, err := os.Stat(cacheDir); os.IsNotExist(err) {
		if err := os.MkdirAll(cacheDir, 0755); err != nil {
			return "", fmt.Errorf("创建缓存目录失败: %v", err)
		}
	}

	// 下载文件
	fmt.Printf("正在下载 %s@%s...\n", metadata.Name, metadata.Version)
	resp, err := pm.httpClient.Get(metadata.DownloadURL)
	if err != nil {
		return "", fmt.Errorf("下载失败: %v", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("下载失败: HTTP %d", resp.StatusCode)
	}

	// 创建临时文件
	tmpFile, err := os.CreateTemp(cacheDir, fmt.Sprintf("%s-*.tmp", metadata.Name))
	if err != nil {
		return "", fmt.Errorf("创建临时文件失败: %v", err)
	}
	tmpFilePath := tmpFile.Name()
	defer os.Remove(tmpFilePath) // 清理临时文件

	// 获取文件大小
	size, err := strconv.Atoi(resp.Header.Get("Content-Length"))
	if err != nil {
		return "", err
	}
	// 创建进度条
	progress := make(chan int64)
	go func() {
		var prev int64
		for p := range progress {
			if p > prev {
				percent := float64(p) / float64(size) * 100
				fmt.Printf("\r下载进度: [%s%s] %d/%d",
					strings.Repeat("=", int(percent/2)),
					strings.Repeat(" ", 50-int(percent/2)),
					p, size)
				prev = p
			}
		}
		fmt.Println()
	}()

	// 使用 TeeReader 计算进度
	reader := io.TeeReader(resp.Body, &progressWriter{
		total:    int64(size),
		progress: progress,
	})

	// 写入下载内容
	if _, err := io.Copy(tmpFile, reader); err != nil {
		return "", fmt.Errorf("写入文件失败: %v", err)
	}
	close(progress) // 关闭进度通道
	// defer tmpFile.Close()
	// 显式关闭文件
	if err := tmpFile.Close(); err != nil {
		return "", fmt.Errorf("关闭临时文件失败: %v", err)
	}

	// 验证校验和
	if pm.config.VerifySSL {
		checksum, err := calculateChecksum(tmpFilePath)
		fmt.Println("计算缓存文件校验和:", checksum)
		if err != nil {
			return "", fmt.Errorf("计算校验和失败: %v", err)
		}
		if checksum != metadata.Checksum {
			return "", fmt.Errorf("校验和不匹配，下载可能损坏")
		}
	}
	// 重命名为正式缓存文件
	if err := os.Rename(tmpFilePath, cachePath); err != nil {
		return "", fmt.Errorf("重命名文件失败: %v", err)
	}

	return cachePath, nil
}

// 计算文件校验和
func calculateChecksum(filePath string) (string, error) {
	file, err := os.Open(filePath)
	if err != nil {
		return "", err
	}
	defer file.Close()

	hash := sha256.New()
	if _, err := io.Copy(hash, file); err != nil {
		return "", err
	}

	return fmt.Sprintf("sha256:%s", hex.EncodeToString(hash.Sum(nil))), nil
}

// 进度条写入器
type progressWriter struct {
	total    int64
	written  int64
	progress chan<- int64
}

func (pw *progressWriter) Write(p []byte) (int, error) {
	n := len(p)
	pw.written += int64(n)
	pw.progress <- pw.written
	return n, nil
}
